准备陆续把之前写下的阅读和学习笔记搬到博客上,这是其中之一。

欢迎批评

第二章 数据模型与查询语言

多数应用程序是由层层叠加的数据模型构建而成的。每一层通过提供一个明确的数据模型来隐藏更低一层的复杂性。例如为开发数据库使用到的API与为使用数据库使用到的API。

1. 对象关系不匹配

ORM 框架可以减少关系模型与对象模型的转换层的代码量,但不能完全隐藏这两个模型间的的差异。例如,一个人的联系方式可能不止一个,我们可以如何将其存储在关系数据库中?

  1. 联系方式单独作为一个表,并将所属人的标识作为其外键。
  2. 得益于 SQL 模型增加了对结构化数据类型、XML 类型和 JSON 类型的支持,我们可以将多值存储在单行内,同时能查询和索引这些文档数据。
  3. 让应用程序来完成将数据编码为 XML 或 JSON 文档的任务,然后将文档数据存储在所属人的文本列中,当应用程序需要其中的数据时不能依靠数据库的查询或索引功能而是自己解析其结构和内容。

相比于关系模型,JSON 更具有局部性。例如,当我们查询一个人的信息时,对于关系模型,我们可能需要进行多次查询或连接多个表,而对于 JSON ,所有信息都在同一个地方。

2. 数据规范化

使用 ID 的好处是,ID 对人类没有任何意义,因而永远不需要改变:ID 可以保持不变,即使它标识的信息发生变化。任何对人类有意义的东西都可能需要在将来某个时候改变——如果这些信息被复制,所有的冗余副本都需要更新。这会导致写入开销,也存在不一致的风险(有些副本被更新了,还有些副本没有被更新)。去除此类重复是数据库规范化(normalization)的关键思想。

对数据进行规范化需要多对一、多对多的关系,关系模型天生支持该特性,但文档模型天生不支持。多对一、多对多的关系需要连接,但文档模型的树结构没必要支持连接。有的文档型数据库为此提供了连接功能。如果使用没有连接的数据库,就需要在应用程序模拟连接。

3. 层次模型、网络模型、关系模型、文档模型

网络模型是层次模型的推导。层次模型的节点只能有一个父节点,网络模型的节点能有多个父节点。这导致了程序员使用网络模型数据库时需要手动选择“访问路径”。

关系模型使用查询优化器自动生成“访问路径”。

文档模型被还原为层次模型。在表示多对一、多对多关系时,文档数据库系统中相关项目都被唯一标识符引用,这个标识符在关系模型中被称作外键,在文档模型中被成为文档引用。该标识符在读取时通过通过连接和后续查询来解析。

4. 文档模型中的架构灵活性,模式 VS. 无模式

文档模型有时被称为“无模式(schemaless)”,但这具有误导性。因为在读取数据时我们会假定某种结构–即隐式模式,但该结构不由文档型数据库强制保证。一个更精确的术语是”读时模式(schema-on-read)”–数据结构只有在读时才被解释,相对应的是“写时模式(schema-on-write)”–传统关系模型要求模式明确且 DBMS 要确保所有数据都符合模式。

  • 读时模式:没有模式,DBMS 不要求写入的数据与现有数据的结构一致,但数据被读取时应用程序需解释其结构。文档模型便是这一类型,这为文档型数据库带来了灵活性。
  • 写时模式:模式明确,这意味在写入时要验证数据是否符合模式。

例如,当一个实体将一个旧属性拆分为两个属性时,对于文档型数据库,旧的数据不需变动,在应用程序增加对旧数据手动拆分的代码就可以。而对于关系型数据库,需要更改表的模式–这时数据库系统要停机。

5. 查询的数据局部性

文档通常以单个连续字符串的形式存储,编码为 JSON、XML 或其二进制变体(例如 MongoDB 的 BSON)。

存储局部性可以避免在插叙时因将数据分割在多个位置而需要的多次索引所花费的磁盘查找时间。

局部性并不只有文档模型在考虑,一些关系型数据库也提供了相关支持。

6.文档与关系数据库的融合

现在,PostgreSQL 和 MySQL 等数据库提供了对 JSON 的支持。关系模型和文档模型的混合是数据库发展的一条很好的路线。

7. SQL的优势

SQL 相当有限的功能性为数据库提供了更多自动优化的空间。

命令代码很难在多个内核和多个机器之间并行化,因为它指定了指令必须以特定顺序执行。声明式语言更具有并行执行的潜力,因为它们仅指定结果的模式,而不指定用于确定结果的算法。在适当情况下,数据库可以自由使用查询语言的并行实现。

8. MapReduce查询

MapReduce 是一个由Google推广的编程模型,用于在多台机器上批量处理大规模的数据。

MapReduce 既不是一个声明式的查询语言,也不是一个完全命令式的查询 API,而是处于两者之间:查询的逻辑用代码片断来表示,这些代码片段会被处理框架重复性调用。它基于 map (也称为 collect )和 reduce (也称为 fold 或 inject )函数,两个函数存在于许多函数式编程语言中。

能够在查询中使用 JavaScript 代码是高级查询的一个重要特性,但这不限于 MapReduce,一些 SQL 数据库也可以用 JavaScript 函数进行扩展。

9. 小结

新的非关系型 “NoSQL” 数据存储在两个主要方向上存在分歧:

  1. 文档数据库的应用场景是:数据通常是自我包含的,而且文档之间的关系非常稀少。
  2. 图形数据库用于相反的场景:任意事物都可能与任何事物相关联。